class FileUploader {
  constructor(file, op = FileUploader.defaultOp) {
    op = Object.assign({}, FileUploader.defaultOp, op)
    /**@type {File}*/
    this.file = file
    this.CHUNK_SIZE = 1024 * 1024 // 1M
    this.chunkIndex = 0
    this.onEnd = op.onEnd
    this.onProgress = op.onProgress
  }
  doSend(chunk) {
    return new Promise((resolve, reject) => {
      let xhr = new XMLHttpRequest()
      xhr.open('post', '/upload')
      function clear() {
        xhr.onload = null
        xhr.onerror = null
      }
      xhr.onload = () => {
        this.onProgress(this.chunkIndex)
        resolve(xhr.responseText)
        clear()
      }
      xhr.onerror = () => {
        reject(xhr.response)
        clear()
      }
      let form = new FormData()
      form.append('chunk', chunk)
      form.append('chunkIndex', this.chunkIndex)
      form.append('fileName', this.file.name)
      xhr.send(form)
    })
  }
  getNextChunk() {
    let chunkIndex = this.chunkIndex
    let start = chunkIndex * this.CHUNK_SIZE
    let next = (chunkIndex + 1) * this.CHUNK_SIZE
    let chunk = this.file.slice(start, next)
    return chunk
  }
  serilize(data) {
    return Object.entries(data)
      .map(([key, value]) => {
        return [encodeURIComponent(key), encodeURIComponent(value)].join('=')
      })
      .join('&')
  }
  merge() {
    return new Promise((resolve, reject) => {
      let xhr = new XMLHttpRequest()
      let data = {
        fileName: this.file.name,
        chunkCount: this.chunkIndex,
      }

      xhr.open('get', `/merge?${this.serilize(data)}`)
      function clear() {
        xhr.onload = null
        xhr.onerror = null
      }
      xhr.onload = () => {
        resolve(xhr.responseText)
        clear()
        this.onEnd()
      }
      xhr.onerror = () => {
        reject(xhr.response)
        clear()
      }
      xhr.send()
    })
  }
  async start() {
    let chunk = this.getNextChunk()
    while (chunk.size > 0) {
      await this.doSend(chunk)
      this.chunkIndex++
      chunk = this.getNextChunk()
    }
    this.merge()
  }
}

FileUploader.defaultOp = {
  onEnd() {
    console.log('send end')
  },
  onProgress(chunkIndex) {
    console.log('发送了 ', chunkIndex, ' 片数据')
  },
}
